﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HtmlAgilityPack;
using System.Data;
using App.Core.DB;
using App.Core.Extensions;

namespace WebScrapper.Implementations.ZukaBuka
{
    public class Baaps : BaseImplementation<App.Core.Base.Model.BaseEntity>
    {
        private const String DOMAIN = "http://www.baaps.org.uk";
        private String URL_FORMAT = "http://www.baaps.org.uk/component/surgeon/search/120/searchword/{0}";
        private String[] Locations = { "Scotland", "North East", "Cumbria", "Yorkshire Humberside", "North West", "East Midlands", "West Midlands", "East of England", "South Central", "London", "South East", "West Country", "Wales", "Northern Ireland", "Ireland", "International" };
        private DataTable _Dt = new DataTable("Doctors");

        #region Data Table Columns
        private const String NAME = "Name";
        private const String DIGREE = "Digree";
        private const String DESCRIPTION = "Description";
        private const String CLINIC_NAME = "Clinic Name";
        private const String TELEPHONE = "Telephone";
        private const String FAX = "Fax";
        private const String EMAIL = "Email";
        private const String WEB_SITE = "Clinic Web Site";
        private const String ADDRESS = "Address";        
        private static String DETAILS_URL = "Details Url";
        #endregion

        public Baaps(System.Windows.Forms.RichTextBox txtStatus) : base(txtStatus)
        {            
            ///Initialize the Scrapped DataTable With Columns
            _Dt.Columns.Add(new DataColumn(NAME));
            _Dt.Columns.Add(new DataColumn(DIGREE));
            _Dt.Columns.Add(new DataColumn(DESCRIPTION));
            _Dt.Columns.Add(new DataColumn(CLINIC_NAME));
            _Dt.Columns.Add(new DataColumn(TELEPHONE));
            _Dt.Columns.Add(new DataColumn(FAX));
            _Dt.Columns.Add(new DataColumn(EMAIL));            
            _Dt.Columns.Add(new DataColumn(ADDRESS));
            _Dt.Columns.Add(new DataColumn(WEB_SITE));
            _Dt.Columns.Add(new DataColumn(DETAILS_URL));            
        }
        public override void StartScrapping(string category)
        {
            foreach (String location in Locations)
            {                
                try
                {
                    UpdateStatusText(String.Format("Processing Location: {0}", location));
                    ProcessLocation(location);
                    UpdateStatusText(String.Format("All Data Scrapped from: {0}{1}{1}", location, Environment.NewLine));                    
                    break;
                }
                catch (Exception ex)
                {
                    UpdateStatusText(String.Format("Error Processing Location: {0}. See following Error:", location));
                    UpdateStatusText(ex.Message);
                    UpdateStatusText(ex.StackTrace);
                }                
            }
            String filePath = DataTableToExcel(_Dt, true, "Baaps.xls"); //DataTableToExcel(_Dt, null, true, "Baaps.xls");
            UpdateStatusText(String.Format("Output File Has been created in '{0}'", filePath));
        }

        private void ProcessLocation(string location)
        {
            string url = String.Format(URL_FORMAT, location);
            HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
            string html = GetAuthenticatedPageContent(url, String.Empty);
            doc.LoadHtml(html);
            if (doc == null || doc.DocumentNode == null)
                UpdateStatusText(String.Format("Cannot get the Doctor's information from: {0}", url));
            else
            {
                HtmlNodeCollection doctors = doc.DocumentNode.SelectNodes("//div[@class='result']");
                if (doctors == null || doctors.Count == 0)
                    UpdateStatusText(String.Format("No doctor found in this URL: {0}", url));
                else
                {
                    foreach (HtmlNode doctor in doctors)
                    {
                        DataRow row = _Dt.NewRow();
                        var titleAnchor = doctor.Descendants("h4")                        
                        .SelectMany(P => P.Descendants("a"));
                        if (titleAnchor != null)
                        {
                            row[NAME] = CleanUpText(titleAnchor.ToList()[0].InnerText);
                            row[DETAILS_URL] = String.Format("{0}{1}", DOMAIN, titleAnchor.ToList()[0].Attributes["href"].Value.Trim());
                            GetDetailsInformation(row);
                        }
                    }
                }
            }
        }

        private void GetDetailsInformation(DataRow row)
        {
            String url = NullHandler.GetString(row[DETAILS_URL]);
            UpdateStatusText(String.Format("Downloading details from {0}", url));
            String html = GetAuthenticatedPageContent(url, String.Empty);
            if (html.IsNullOrEmpty())
                UpdateStatusText(String.Format("Unable to get details from {0}", url));
            else
            {
                HtmlAgilityPack.HtmlDocument doc = new HtmlDocument();
                doc.LoadHtml(html);
                if (doc == null || doc.DocumentNode == null)
                    UpdateStatusText(String.Format("Unable to get details from {0}", url));
                else
                {
                    HtmlNode content = doc.DocumentNode.SelectSingleNode("//div[@id='content']");
                    HtmlNodeCollection descriptions = content.SelectSingleNode("//div[@class='description']").SelectNodes("p");
                    if (descriptions != null && descriptions.Count > 0)
                    {
                        row[DIGREE] = CleanUpText(descriptions[0].InnerText);
                        row[DESCRIPTION] = CleanUpText(descriptions[1].InnerText);
                    }
                    ///Add the Row to the Collection
                    _Dt.Rows.Add(row);
                    ///Now Extract the Clinics for this Doctor
                    LoadClinics(content);
                }
            }
        }

        private void LoadClinics(HtmlNode content)
        {
            UpdateStatusText("Loading Clinics...");
            HtmlNodeCollection clinics = content.SelectNodes("h4");
            HtmlNodeCollection detailAddresses = content.SelectNodes("//div[@class='detailsAddress']");
            HtmlNodeCollection detailContacts = content.SelectNodes("//div[@class='detailsContact']");
            if (clinics == null || clinics.Count == 0)
                UpdateStatusText("No Clinic found.");
            else
            {
                UpdateStatusText(String.Format("Total {0} Clinics found.", clinics.Count));
                for (int i = 0; i < clinics.Count; i++)
                {
                    DataRow row = _Dt.NewRow();
                    row[CLINIC_NAME] = CleanUpText(clinics[i].InnerText);
                    row[ADDRESS] = CleanUpText(detailAddresses[i].InnerText);
                    HtmlNode contact = detailContacts[i];
                    HtmlNodeCollection headings = contact.SelectNodes("strong");
                    if (headings == null || headings.Count == 0)
                        UpdateStatusText("No Contact Info Found for this clinic.");
                    else
                    {
                        foreach (HtmlNode heading in headings)
                        {
                            String caption = CleanUpText(heading.InnerText);
                            if (String.Compare(caption, "Telephone:", true) == 0)
                                row[TELEPHONE] = heading.NextSibling.InnerText;
                            else if (String.Compare(caption, "Fax:", true) == 0)
                                row[FAX] = heading.NextSibling.InnerText;
                            else if (String.Compare(caption, "Email:", true) == 0)
                                row[EMAIL] = CleanUpText(heading.NextSibling.NextSibling.InnerText);
                            else if (String.Compare(caption, "Website:", true) == 0)
                                row[WEB_SITE] = heading.NextSibling.NextSibling.Attributes["href"].Value;
                        }
                        //HtmlNode heading = headings[0];
                    }
                    _Dt.Rows.Add(row);
                }
            }
        }
        

        public override string OutputFile(List<App.Core.Base.Model.BaseEntity> collection, bool addColumnHeader, string outputFileName)
        {
            throw new NotImplementedException();
        }
    }    
}
